﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace OrangePrj
{
    [Serializable]
    public class WorkList : List<Work>, ICloneable
    {
        private int maxId;

        public WorkList() { }
        public WorkList(WorkList worklist)
        {
            foreach (Work w in worklist)
            {
                Work tempWork = (Work)w.Clone();
                this.Add(tempWork);
            }
        }
        public void Add(Work work)
        {
            if (work.id == 0)
                work.id = maxId++;
            base.Add(work);
        }
        public void Add(string name, string descr)
        {
            Add(new Work(name, descr));
        }
        public void ReplaceWork(Work work_new, Work work_old)
        {
            for (int i = 0; i < this.Count; i++)
                if (this[i].Equals(work_old))
                {
                    this[i] = (Work)work_new.Clone();
                    this.UpdateWork(this[i]);
                }
        }
        public void DeleteWork(string name)
        {
            Work w = this.Where(work => work.Name == name).FirstOrDefault();
            DeleteWork(w);
        }
        public void DeleteWork(Work w)
        {
            DeleteWork(w.id);
        }
        public string DeleteWork(int id)
        {
            string message = "";
            Work w = this.getWorkByID(id);
            WorkList tmp_DepWorks = w.DepWorks;
            List<int> tmp_DepInd = w.DepInd;

            this.Remove(w);
            foreach (Work wd in this)
            {
                if (wd.DepInd.RemoveAll(i => i == id) != 0)
                {
                    wd.DepWorks.RemoveAll(work => work.id == id);
                    wd.DepWorks.AddRange(tmp_DepWorks);
                    wd.DepInd.AddRange(tmp_DepInd);
                    message = "При удалении данной работы, изменятся зависимости других работ.";
                }
            }
            return message;
        }
        public void UpdateWork(Work w)
        {
            for (int i = 0; i < this.Count; i++)
            {
                if (this[i].Equals(w))
                {
                    this[i] = w;
                }
                for (int d = 0; d < this[i].DepWorks.Count; d++)
                {
                    if (this[i].DepWorks[d].Equals(w))
                    {
                        this[i].DepWorks[d] = w;
                    }
                }
            }
        }
        public void DeleteMissedWorks()
        {
            this.RemoveAll(work => work.isMissed);

            for (int i = 0; i < this.Count; i++)
            {
                foreach (Work w in this[i].DepWorks)
                {
                    if (w.isMissed)
                        this[i].DepInd.Remove(w.id);
                }
            }

            for (int i = 0; i < this.Count; i++)
            {
                this[i].DepWorks.RemoveAll(work => work.isMissed);
            }
        }
        public Work getWorkByID(int id)
        {
            return this.Where(work => work.id == id).FirstOrDefault();
        }
        public Work getWorkByName(string name)
        {
            return this.Where(work => work.Name == name).FirstOrDefault();
        }
        public int getIdByWorkName(string name)
        {
            return getWorkByName(name).id;
        }
        public int getMaxRank()
        {
            int r = 0;
            foreach (Work w in this)
            {
                if (w.rank > r)
                    r = w.rank;
            }
            return r;
        }
        public void RefreshWorkTime()
        {
            for (int i = 0; i <= this.getMaxRank(); i++)
                foreach (Work w in this)
                    if (w.rank == i)
                    {
                        w.timestart = w.getMaxEndtime4Depend();
                        w.CalcEndTime();
                    }
        }
        public void setReverseDepWorks()
        {
            foreach (Work work in this)
            {
                foreach (Work w in work.DepWorks)
                {
                    w.ReversDepWorks.Add(work);
                }
            }
        }
        public void Ranking()
        {
            for (int i = 0; i < this.Count; i++)
            {
                if (this[i].hasDepends() == false)
                    this[i].rank = 0;
                else
                {
                    this[i].setMaxRank();
                    this.UpdateWork(this[i]);
                }
            }
        }
        public double getFullResources()
        {
            double Res = 0.0;
            foreach (Work w in this)
            {
                Res += w.Time * w.Resource.Amount;
            }
            return Res;
        }
        public double getPrjTime()
        {
            this.RefreshWorkTime();
            double t = 0;
            foreach (Work w in this)
            {
                if (w.timeend > t)
                    t = w.timeend;
            }
            return t;
        }  
        public Object Clone()
        {
            return new WorkList(this);
        }
    }
}
